package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/zheng-ji/goSnowFlake"
	"gorm.io/gorm"
	"guns-go/global"
	"guns-go/model"
	"guns-go/model/request"
	"guns-go/model/response"
	"guns-go/utils"
	"guns-go/utils/file"
	"mime/multipart"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

func SaveSysFileInfo(info *model.SysFileInfo, tx *gorm.DB) error {
	return tx.Create(info).Error
}

func GetSysFileInfo(fileId int) (err error, sysFileInfo *model.SysFileInfo) {

	var fileInfo *model.SysFileInfo
	err = global.GVA_DB.Where("id = ?", fileId).Find(&fileInfo).Error

	return err, fileInfo
}

func DeleteSysFileInfo(fileId int, tx *gorm.DB) error {
	return tx.Delete(model.SysFileInfo{}, "id =  ?", fileId).Error
}

func Preview(sysFileInfoParam *request.SysFileInfoParam, c *gin.Context) error {

	var fileBytes []byte

	//根据文件id获取文件信息结果集
	err, sysFileInfoResult := getFileInfoResult(sysFileInfoParam.Id)

	if err != nil {
		return err
	}
	//获取文件后缀
	fileSuffix := strings.ToLower(sysFileInfoResult.FileSuffix)
	//获取文件字节码
	fileBytes = sysFileInfoResult.FileBytes

	if isPic(fileSuffix) {
		c.Header("content-type", "image/jpeg")
		c.Data(response.DefaultSuccessCode, "image/jpeg", fileBytes)
	} else {
		err = errors.New("预览文件异常，您预览的文件类型不支持或文件出现错误")
	}
	return err
}

func getFileInfoResult(fileId int) (err error, r *response.SysFileInfoResult) {

	var fileBytes []byte

	err, sysFileInfo := GetSysFileInfo(fileId)

	if sysFileInfo.Id == 0 {
		return errors.New("文件不存在"), nil
	}

	fileOperator := file.NewFileOperator()

	// 返回文件字节码
	fileBytes, err = fileOperator.GetFileBytes(global.DefaultBucket, sysFileInfo.FileObjectName)

	if err != nil {
		return errors.New("获取文件流错误" + err.Error()), nil
	}

	sysFileInfoResult := new(response.SysFileInfoResult)

	err = utils.SimpleCopyProperties(sysFileInfoResult, sysFileInfo)

	if err != nil {
		return err, nil
	}

	sysFileInfoResult.FileBytes = fileBytes

	return err, sysFileInfoResult
}

//根据文件后缀判断是否图片
func isPic(fileSuffix string) bool {

	suffix := global.MediaType(fileSuffix)

	return suffix == global.ImgJpg ||
		suffix == global.ImgJpeg ||
		suffix == global.ImgPng ||
		suffix == global.ImgGif ||
		suffix == global.ImgTif ||
		suffix == global.ImgBmp
}

func UploadFile(header *multipart.FileHeader) (error, *int64) {

	// 生成文件的唯一id
	iw, err := goSnowFlake.NewIdWorker(1)
	if err != nil {
		return err, nil
	}

	fileId, err := iw.NextId()

	if err != nil {
		return err, nil
	}

	// 获取文件原始名称
	originalFilename := header.Filename

	// 获取文件后缀
	var fileSuffix string

	if originalFilename != "" {
		fileSuffix = utils.SubAfter(originalFilename, ".", true)
	}

	// 生成文件的最终名称
	finalName := strconv.Itoa(int(fileId)) + "." + fileSuffix

	// 存储文件
	f, err := header.Open()
	fileOperator := file.NewFileOperator()
	err = fileOperator.StorageFileWithReader(global.DefaultBucket, finalName, f)

	if err != nil {
		return err, nil
	}
	// 文件大小kb
	fileSizeKb := header.Size

	//计算文件大小信息
	fileSizeInfo := utils.ReadableFileSize(fileSizeKb)

	// 存储文件信息
	sysFileInfo := new(model.SysFileInfo)

	sysFileInfo.Id = int(fileId)
	//阿里云
	sysFileInfo.FileLocation = 1
	sysFileInfo.FileBucket = global.DefaultBucket
	sysFileInfo.FileObjectName = finalName
	sysFileInfo.FileOriginName = originalFilename
	sysFileInfo.FileSuffix = fileSuffix
	sysFileInfo.FileSizeKb = int(fileSizeKb)
	sysFileInfo.FileSizeInfo = fileSizeInfo

	tx := global.GVA_DB.Begin()

	err = SaveSysFileInfo(sysFileInfo, tx)

	if err != nil {
		tx.Rollback()
		return err, nil
	}
	tx.Commit()
	// 返回文件id
	return nil, &fileId
}

func SysFileInfoPage(sysFileInfoParam *request.SysFileInfoParam, c *gin.Context) (error, *response.PageResult) {

	var sysFileInfos []*model.SysFileInfo

	// 构造条件
	db := global.GVA_DB

	// 拼接查询条件-文件存储位置（1:阿里云，2:腾讯云，3:minio，4:本地）
	if sysFileInfoParam != nil {
		if sysFileInfoParam.FileLocation != 0 {
			db = db.Where("file_location like ? ", "%"+strconv.Itoa(int(sysFileInfoParam.FileLocation))+"%")
		}

		// 拼接查询条件-文件仓库
		if sysFileInfoParam.FileBucket != "" {
			db = db.Where("file_bucket like ? ", "%"+sysFileInfoParam.FileBucket+"%")
		}

		// 拼接查询条件-文件名称（上传时候的文件名）
		if sysFileInfoParam.FileOriginName != "" {
			db = db.Where("file_origin_name like ? ", "%"+sysFileInfoParam.FileOriginName+"%")
		}
	}

	var totalCount int64

	err := db.Find(&sysFileInfos).Count(&totalCount).Error

	if err != nil {
		return err, nil
	}

	pageNo, pageSize, db := utils.DefaultPage(c, db)

	err = db.Find(&sysFileInfos).Error

	if err != nil {
		return err, nil
	}

	return err, utils.CoverToPageResult(pageNo, pageSize, totalCount, sysFileInfos)
}

func Download(sysFileInfoParam *request.SysFileInfoParam, c *gin.Context) error {

	err, sysFileInfoResult := getFileInfoResult(sysFileInfoParam.Id)

	fileName := sysFileInfoResult.FileOriginName

	fileBytes := sysFileInfoResult.FileBytes

	// 设置返回头并返回数据
	fileContentDisposition := "attachment; filename=\"" + url.QueryEscape(fileName) + "\""
	c.Header("Content-Type", "application/octet-stream;charset=UTF-8")
	c.Header("Content-Length", strconv.Itoa(len(fileBytes)))
	c.Header("Access-Control-Allow-Origin", "*")
	c.Header("Access-Control-Expose-Headers", "Content-Disposition")
	c.Header("Content-Disposition", fileContentDisposition)
	c.Data(http.StatusOK, "application/octet-stream;charset=UTF-8", fileBytes)

	return err
}

//判断文件是否存在
func AssertFile(field int) error {

	err, sysFileInfo := GetSysFileInfo(field)

	if err != nil {
		return err
	}

	if sysFileInfo == nil || sysFileInfo.Id == 0 {
		return errors.New("您查询的该条记录不存在")
	}

	return nil
}

func SysFileInfoDelete(sysFileInfoParam *request.SysFileInfoParam) error {

	// 查询文件的信息
	err, sysFileInfo := GetSysFileInfo(sysFileInfoParam.Id)

	if err != nil {
		return err
	}

	if sysFileInfo.Id != 0 {

		tx := global.GVA_DB.Begin()
		// 删除文件记录
		err = DeleteSysFileInfo(sysFileInfo.Id, tx)

		if err != nil {
			tx.Rollback()
			return err
		}

		// 删除具体文件
		fileOperator := file.NewFileOperator()

		err = fileOperator.DeleteFile(sysFileInfo.FileBucket, sysFileInfo.FileObjectName)

		if err != nil {
			tx.Rollback()
			return err
		}
		tx.Commit()
	}
	return nil
}
